﻿/*----------------------------------------------------------------
// 公司名称：公司名称
//
// 产品名称：Gaf
//
// 创 建 人：netcasewqs
// 创建日期：2022/3/4
// 邮    箱：netcasewqs@qq.com
//
// Copyright (C) 2022 Gaf，保留所有权利。
//
//----------------------------------------------------------------*/

namespace Gaf.Impl;

internal abstract class ClassLoader 
{
    internal AssemblyLoadContext _assemblyLoader = null!;
    internal readonly Dictionary<string, string> _managedLibsPath = new();
    internal readonly Dictionary<string, string> _unManagedLibsPath = new();

    internal List<UnmanagedLibrary> _unmanagedLibraries = new();

    public ClassLoader(Dictionary<string, string> managedLibsPath, Dictionary<string, string> unManagedLibsPath, AssemblyLoadContext assemblyLoad)
    {
        _managedLibsPath = managedLibsPath;
        _unManagedLibsPath = unManagedLibsPath;
        _assemblyLoader = assemblyLoad;
    }

    public static ClassLoader Create(AddinActivator activator)
    {
        var options = activator._framework.Options;
        if (activator.Addin.IsLiteAddin) return new LiteClassLoader(activator._framework);

        if (options.AddinIsolation) return new IsolationClassLoader(activator);

        return new SharedClassLoader(activator);
    }

    public string? Name => _assemblyLoader.Name;
    /// <summary>
    /// 是否可回收的
    /// </summary>
    public bool IsCollectible => _assemblyLoader.IsCollectible;

    /// <summary>
    /// 是否是轻量级插件的ClassLoader
    /// </summary>
    public virtual bool IsLite => false;

    /// <summary>
    /// 是否是隔离式ClassLoader, 如果是隔离式，那么每个ClassLoader 都公用一个AssemblyLoaderContext,否则每个ClassLoader 都独占一个AssemblyLoaderContext
    /// </summary>
    public virtual bool IsIsolation => false;

    public virtual IEnumerable<Assembly> Assemblies => _assemblyLoader.Assemblies;

    public virtual Assembly LoadAssembly(string assemblyFilePath)
    {
        return _assemblyLoader.LoadFromAssemblyPath(assemblyFilePath);
    }

    public virtual void LoadUnmanagedDllFromPath(string unmanagedDllFile)
    {
        var lib = Win32.LoadUnmanagedLibrary(unmanagedDllFile);
        _unmanagedLibraries.Add(lib);

    }

    public void SafeExecute(Action action)
    {
        try
        {
            _assemblyLoader.Resolving += OnAssemblyResolving; ;
            action();
        }
        finally
        {
            _assemblyLoader.Resolving -= OnAssemblyResolving;
        }
    }

    protected virtual Assembly? OnAssemblyResolving(AssemblyLoadContext context, AssemblyName assemblyName)
    {
        if (assemblyName.Name != null)
        {
            if (_managedLibsPath.TryGetValue(assemblyName.Name, out var dllPath))
                return LoadAssembly(dllPath);
        }

        return default;
    }

    public bool IsSystemAssembly(Assembly asm)
    {
        var dllFile = Path.Combine(Name!, asm.GetName().Name! + ".dll");
        return Gac.SharedFrameworkDLLs.Contains(dllFile);
    }

    public bool IsCustomAssembly(Assembly asm) => !IsSystemAssembly( asm);

    public virtual void Unload()
    {
        if (IsCollectible) _assemblyLoader.Unload();
        foreach (var lib in _unmanagedLibraries)
            lib.Dispose();

        _unmanagedLibraries.Clear();
    }
}
